package com.ruoyi.qywx.service;

import com.ruoyi.common.core.cache.Meta;
import com.ruoyi.common.function.InsertBatchFunction;
import com.ruoyi.common.function.SelectPageAllFunction;
import com.ruoyi.common.utils.CollectionUtils;
import com.ruoyi.common.utils.StrUtils;
import com.ruoyi.qywx.callback.txl.ExtChatEncrypt;
import com.ruoyi.qywx.callback.txl.ExternalTagEncrypt;
import com.ruoyi.qywx.callback.txl.ExternalUserEncrypt;
import com.ruoyi.qywx.callback.txl.PartyEncrypt;
import com.ruoyi.qywx.entity.ContactEntity;
import com.ruoyi.qywx.entity.ContactTag;
import com.ruoyi.qywx.entity.ContactTagGroup;
import com.ruoyi.qywx.entity.Dept;
import com.ruoyi.qywx.enums.QyChatUpdateEvent;
import com.ruoyi.qywx.enums.QyNotificationType;
import com.ruoyi.qywx.enums.TagEnum;
import com.ruoyi.qywx.getway.api.SyncAppApi;
import com.ruoyi.qywx.getway.entity.*;
import com.ruoyi.qywx.mapper.SyncAppMapper;
import com.ruoyi.qywx.service.inters.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author : hcl
 * @Date : 2023/8/9 15:42
 * 同步企业微信接口数据
 */
@Service
@Slf4j
public class SyncQiyeServiceImpl implements SyncQiyeService {
    @Resource
    private SyncAppMapper syncAppMapper;
    @Autowired
    private ContactService contactService;
    @Autowired
    private ContactTagServic tagServic;
    @Autowired
    private QyMessageEventService qyMessageEventService;
    @Autowired
    private ExtContactService extContactService;
    @Autowired
    private ExtGroupChatService chatService;

    @Override
    @Async("qywxCallbackExecutor")
    public void syncAppTxl(Meta meta) {
        // 同步部门
        List<QyDept> qyDepts = syncDepts(meta);
        // 同步部门下员工
        if (CollectionUtils.isNotEmpty(qyDepts)) {
            contactService.deleteUser(null, meta.getTeamId());
            syncQiyeUsers(qyDepts, meta);
        }
    }

    @Override
    @Async("qywxCallbackExecutor")
    public void syncQiyeTags(Meta meta) {
        List<QyTagGroup> qyTagGroup = SyncAppApi.qywxTagsPost(meta, null, null);
        if (Objects.isNull(qyTagGroup)) return;

        List<ContactTagGroup> oldTagGroupds = tagServic.selectQiyeGroups(meta, null);

        Map<String, ContactTagGroup> groupMap = oldTagGroupds.stream()
                .collect(Collectors.toMap(ContactTagGroup::getWxId, e -> e));

        qyTagGroup.stream().filter(g -> !g.isDeleted()).forEach(tagGroup -> {
            ContactTagGroup group = ContactTagGroup.builder()
                    .teamId(meta.getTeamId())
                    .type(TagEnum.QYWX.ordinal())
                    .groupName(tagGroup.getGroup_name())
                    .wxId(tagGroup.getGroup_id())
                    .build();
            Long groupId = this.updateQiyeTagGroup(group, groupMap);
            this.updateQiyeTag(tagGroup.getTag(), groupId, meta.getTeamId());
        });
        // 移除不存在的分组
        if (log.isDebugEnabled()) {
            log.debug("删除多余的标签分组，删除数：" + groupMap.size());
        }
        tagServic.deleteQywxNoexistGroups(groupMap.values()
                .stream()
                .map(ContactTagGroup::getId)
                .collect(Collectors.toList()));
    }

    private void updateQiyeTag(List<QyTag> tag, Long groupId, Long teamId) {
        if (CollectionUtils.isEmpty(tag)) return;
        InsertBatchFunction<ContactTag> insert = tagServic::insertTag;
        SelectPageAllFunction<ContactTag> select = oldTags -> {
            // oldTags: 现有分组下所有的tag
            Map<String, ContactTag> oldTagsMap = oldTags.stream()
                    .collect(Collectors.toMap(ContactTag::getWxId, oldTag -> oldTag));

            List<ContactTag> tags = tag.stream()
                    .filter(wxTag -> {
                        if (wxTag.isDeleted()) {
                            return false;
                        }
                        String wxId = wxTag.getId();
                        if (oldTagsMap.containsKey(wxId)) {
                            String tagName = wxTag.getName();
                            ContactTag contactTag = oldTagsMap.get(wxId);
                            if (!tagName.equals(contactTag.getName())) {
                                contactTag.setName(tagName);
                                tagServic.updateTagName(contactTag);
                            }
                            oldTagsMap.remove(wxId);
                            return false;
                        }
                        return true;
                    }).map(wxTag ->
                            ContactTag.builder()
                                    .groupId(groupId)
                                    .name(wxTag.getName())
                                    .wxId(wxTag.getId())
                                    .type(TagEnum.QYWX.ordinal())
                                    .teamId(teamId)
                                    .build()
                    ).collect(Collectors.toList());
            insert.batch(50, tags);
            //删除不存在的表情
            if (log.isDebugEnabled()) {
                log.debug("删除多余的标签数据，删除数：" + oldTagsMap.size());
            }
            tagServic.deleteTags(oldTagsMap.values()
                    .stream()
                    .map(ContactTag::getId)
                    .collect(Collectors.toList()));
        };
        select.select(1, () -> tagServic.selectTagsByGroupId(groupId));
    }

    /**
     * 更新数据库企业标签分组
     *
     * @param groupMap 旧数据
     * @return 返回分组id
     */
    private Long updateQiyeTagGroup(ContactTagGroup group,
                                    Map<String, ContactTagGroup> groupMap) {
        if (groupMap.containsKey(group.getWxId())) {
            ContactTagGroup oldGroup = groupMap.get(group.getWxId());
            if (oldGroup.getGroupName().equals(group.getGroupName())) {
                // 移除已经存在的数据
                groupMap.remove(group.getWxId());
                return oldGroup.getId();
            }
            group.setId(oldGroup.getId());
            tagServic.updateTagGroupById(group);
            // 移除已经存在的数据
            groupMap.remove(group.getWxId());
        } else {
            tagServic.insertTagGroup(group);
        }
        return group.getId();
    }

    /**
     * 根据项目 同步 部门信息
     */
    @Override
    public List<QyDept> syncDepts(Meta teamMeta) {
        List<QyDept> depts = SyncAppApi.departmentsGet(teamMeta);
        if (CollectionUtils.isNotEmpty(depts)) {
            List<Dept> oldDepts = contactService.selectTeamDept(teamMeta.getTeamId());
            if (CollectionUtils.isNotEmpty(oldDepts)) {
                syncAppMapper.deleteParty(null, teamMeta.getTeamId());
            }
            // 未录入部门时，直接新增所有wx返回部门
            List<PartyEncrypt> encrypts = depts.stream()
                    .map(this::deptToPartyEncrypt)
                    .collect(Collectors.toList());
            createParties(encrypts, teamMeta.getTeamId());
            return depts;
        }
        return Collections.emptyList();
    }

    private void syncQiyeUsers(List<QyDept> depts, Meta meta) {
        Set<QyContact> contactEntities = new HashSet<>(64);
        for (QyDept dept : depts) {
            contactEntities.addAll(SyncAppApi.departmentUsers(dept.getId(), meta));
        }
        if (CollectionUtils.isNotEmpty(contactEntities)) {
            createUsers(contactEntities, meta.getTeamId());
        }
    }

    @Transactional
    @Override
    public void createUser(QyContact qyContact, Long teamId) {
        contactService.createUser(turnContactEntity(qyContact, teamId));
    }

    private void createUsers(Set<QyContact> contactEntities, Long teamId) {
        if (CollectionUtils.isNotEmpty(contactEntities)) {
            List<String> collect = contactEntities.stream().map(QyContact::getUserId).collect(Collectors.toList());
            contactService.selectContactByIds(collect, teamId);
            InsertBatchFunction<ContactEntity> batch = contactService::createUsers;
            batch.batch(20, contactEntities.stream().map(c -> turnContactEntity(c, teamId)).collect(Collectors.toList()));
        }
    }

    @Override
    public void updateUser(QyContact qyContact, Long teamId) {
        contactService.updateUser(turnContactEntity(qyContact, teamId));
    }

    @Override
    public void deleteUser(String userId, Long teamId) {
        contactService.deleteUser(userId, teamId);
    }

    @Transactional
    @Override
    public void deleteParty(Long partyId, Long teamId) {
        syncAppMapper.deleteParty(partyId, teamId);
    }

    @Transactional
    @Override
    public void deletePartys(Collection<Long> deptIds, Long teamId) {
        if (CollectionUtils.isNotEmpty(deptIds)) {
            syncAppMapper.deletePartys(deptIds, teamId);
        }
    }

    @Transactional
    @Override
    public void updateParty(PartyEncrypt encrypt, Long teamId) {
        syncAppMapper.updateParty(encrypt, teamId);
    }

    @Transactional
    @Override
    public void createParty(PartyEncrypt party, Long teamId) {
        syncAppMapper.createParty(party, teamId);
    }

    @Transactional
    @Override
    public void createParties(List<PartyEncrypt> party, Long teamId) {
        syncAppMapper.createParties(party, teamId);
    }

    @Override
    public void addExternalContact(ExternalUserEncrypt encrypt, Meta meta) {
        QyWelcome welcome = qyMessageEventService.sendExternalWelcome(encrypt, meta);
        String bindTags = null, remark = null;
        if (welcome != null) {
            bindTags = welcome.getBindTags();
            remark = welcome.getRemark();
        }
        extContactService.addExternalContact(encrypt, bindTags, remark, meta, tagServic);
    }

    @Override
    public void editExternalContact(ExternalUserEncrypt encrypt, Meta meta) {
        extContactService.editExternalContact(encrypt, meta, tagServic);
    }

    @Override
    public void delExternalContact(ExternalUserEncrypt encrypt, Long teamId) {
        extContactService.deleteExternalContact(encrypt.getExternalUserID(), encrypt.getUserID(), teamId);
    }

    @Override
    public void delFollower(ExternalUserEncrypt encrypt, Long teamId) {

        extContactService.deleteFollower(encrypt.getExternalUserID(), encrypt.getUserID(), teamId);
    }

    @Override
    public void notificationCreateTag(ExternalTagEncrypt encrypt, Meta meta, QyNotificationType type) {
        switch (type) {
            case CREATE_TAG:
                tagServic.insertQywxTags(Collections.singletonList(encrypt.getId()), meta, tagServic::insertTag);
                break;
            case UPDATE_TAG:
                tagServic.updateQywxTags(Collections.singletonList(encrypt.getId()), meta);
                break;
            case UPDATE_TAG_GROUP:
                tagServic.updateQywxTagGroup(encrypt.getId(), meta);
                break;
            case DELETE_TAG:
                tagServic.deleteTag(encrypt.getId(), meta.getTeamId());
                break;
            case DELETE_TAG_GROUP:
                tagServic.deleteTagGroup(encrypt.getId(), meta.getTeamId());
                break;
        }
    }

    private PartyEncrypt deptToPartyEncrypt(QyDept dept) {
        PartyEncrypt encrypt = new PartyEncrypt();
        encrypt.setId(dept.getId());
        encrypt.setName(dept.getName());
        encrypt.setParentId(dept.getParentId());
        encrypt.setOrder(dept.getOrder());
        return encrypt;
    }

    private ContactEntity turnContactEntity(QyContact c, Long teamId) {
        ContactEntity contact = new ContactEntity();
        contact.setUserId(c.getUserId());
        contact.setName(c.getName());
        contact.setOpenId(StrUtils.defaultString(c.getOpenUserId()));
        contact.setAvatar(StrUtils.defaultString(c.getAvatar()));
        contact.setDeptId(c.getDeptId());
        contact.setDepartments(CollectionUtils.join(c.getDepartments(), ","));
        contact.setStatus(c.getStatus());
        contact.setTeamId(teamId);
        return contact;
    }

    @Override
    public void createExternalChat(Meta meta, String chatId) {
        chatService.informCreateChat(meta, chatId);
    }

    @Override
    public void updateExternalChat(Meta meta, ExtChatEncrypt encrypt) {
        QyChatUpdateEvent updateEvent = QyChatUpdateEvent.valueOf(encrypt.getUpdateDetail().toUpperCase());
        switch (updateEvent) {
            case ADD_MEMBER:
                chatService.addMember(meta, encrypt);
                break;
            case DEL_MEMBER:
                chatService.deleteMember(meta, encrypt);
                break;
            case CHANGE_OWNER:
                chatService.changeChatInfo(meta, encrypt, "owner");
                break;
            case CHANGE_NAME:
                chatService.changeChatInfo(meta, encrypt, "name");
                break;
            case CHANGE_NOTICE:
                chatService.changeChatInfo(meta, encrypt, "notice");
                break;
        }
    }

    @Override
    public void dismissExternalChat(Meta meta, String chatId) {
    }
}
